package com.share.tx.util;

import java.lang.reflect.Method;
import java.util.List;

import javax.annotation.Resource;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.MyBatisSystemException;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.BadSqlGrammarException;
import org.springframework.jdbc.CannotGetJdbcConnectionException;
import org.springframework.stereotype.Service;

import com.mchange.v2.resourcepool.CannotAcquireResourceException;

/**
 * <p>Title: DasAdvisor </p>
 * <p>Description: sql语句执行时间 返回size通知 </p>
 * 
 * 
 * 
 */
@Service
public class MyAspect_aop1 implements MethodInterceptor {
	private static final String SERVICE_NAME="UnifEdbAdvisor";
	private static final String MESSAGE = 
			"A ResourcePool could not acquire a resource from its primary factory or source";


	@Resource
	private SqlSessionFactory sqlSessionFactory;

	
	@Override
	public Object invoke(MethodInvocation invocation) throws Throwable {
		Object invokeResultObject = null;
		int count = 0;
		int retry_count = 1;
		boolean execRsFlag = false;
		String flag = getMethodString(invocation);
		do{
			SqlResult sqlResult = exec(invocation, count);
			invokeResultObject = sqlResult.object;
			execRsFlag = sqlResult.res;
			count++;
		}while( execRsFlag == false && count <= retry_count);
		if(execRsFlag == false && count == retry_count+1 ){
			MyBatisSystemException e = new MyBatisSystemException(null);
			System.out.println(flag + " 共重试：" + retry_count + "次，失败，直接抛异常." + e.toString());
			throw e;
		}
		return invokeResultObject;
	}

	private SqlResult exec(MethodInvocation invocation, int count) throws Throwable{
		SqlResult result = new SqlResult();
		String flag = getMethodString(invocation);
		long start = System.currentTimeMillis();
		try {
			result.object = invocation.proceed();
			result.res = true;
			StringBuilder sb = new StringBuilder();
			long time = System.currentTimeMillis() - start;
			sb.append("Executed " + flag + " [ timeCost -> " + time
					+ " ms , result(size) -> ");
			if (result instanceof List) {
				sb.append(((List<?>) result).size());
			} else {
				sb.append(result);
			}
			sb.append(" ]");
			if (time > 1000) {
				//CAT.error(sb.toString());
				//超过1000ms打印具体sql
				logHandler(invocation, sb);
			} else {
				System.out.println(sb.toString());
			}
		}catch(CannotGetJdbcConnectionException e){
			System.out.println(e);
			throw e;
		}catch(CannotAcquireResourceException e){
			System.out.println(e);
			throw e;
		}catch (MyBatisSystemException e) {//BadSqlGrammarException
			result.res = false;
			System.out.println(flag + " 执行第：" + (count+1) + "次，失败 ." + e.getMessage());
			Thread.sleep(2000);
		}catch (DataAccessException e) {
			throw e;
		}
		return result;
	}
	

	private void logHandler(MethodInvocation invocation, StringBuilder sb) {
		String name = invocation.getMethod().getDeclaringClass().getName() + "." + invocation.getMethod().getName();
		if (name != null && name.contains("Mapper")) {
			String sql = getMyBatisSql(name, null, sqlSessionFactory);
			sb.append("超时sql: "+sql);
			System.out.println(sb.toString());
		}
	}

	/**
	 * getMyBatisSql: 获取sql语句的输出文本
	 * @param id parameter sqlSessionFactory
	 * @return sql语句
	 */
	private String getMyBatisSql(String id, Object[] parameter,SqlSessionFactory sqlSessionFactory) { 
		String sql = "";
		try {
			MappedStatement ms = sqlSessionFactory.getConfiguration().getMappedStatement(id); 
			BoundSql boundSql = ms.getBoundSql(parameter);  
			sql = boundSql.getSql(); 
		} catch (Exception e) {
			System.out.println(e.getMessage());
		}
		return sql;
	}

	/**
	 * GetMethodString: 获取MethodInvocation的输出文本
	 * @param invocation
	 * @return 输出文本
	 */
	private static String getMethodString(MethodInvocation invocation) {
		Method method = invocation.getMethod();
		StringBuffer sb = new StringBuffer();
		sb.append(method.getDeclaringClass().getSimpleName());
		sb.append("@[");
		sb.append(method.getReturnType().getSimpleName()).append(" ");
		sb.append(method.getName());
		sb.append("(");
		@SuppressWarnings("rawtypes")
		Class[] params = method.getParameterTypes();
		for (int j = 0; j < params.length; j++) {
			// 参数是泛型是，无法区分两个方法，后续补充
			sb.append(params[j].getSimpleName());
			if (j < (params.length - 1)) {
				sb.append(",");
			}
		}
		sb.append(")]");
		return sb.toString();
	}

	class SqlResult{
		boolean res = false;
		Object object = null;
	}
}
